// token.cpp : Defines the exported functions for the DLL application.
//

#include "stdafx.h"
#include "token.hpp"

token::token(unsigned short _len): generator(0x00, 0x7F), _max_token_len(_len) {}

token::token(unsigned short _len, unsigned short _min_distr_value, unsigned short _max_distr_value, const std::string& _seed_status_file): 
	generator(_min_distr_value, _max_distr_value, _seed_status_file), _max_token_len(_len) {}

token::token(unsigned short _len, unsigned short _min_distr_value, unsigned short _max_distr_value, const std::string& _allowed_punct, const std::string& _forbidden_punct, bool _allow_first_as_punct, const std::string& _seed_status_file): 
	generator(_min_distr_value, _max_distr_value, _seed_status_file), _max_token_len(_len),  allowed_punct(_allowed_punct), forbidden_punct(_forbidden_punct), allow_first_as_punct(_allow_first_as_punct) {}

const std::string token::experiment()
{

	std::string str;
	unpack();
#ifdef _DEBUG 
	std::cout << "[token_len] experiment: after unpack()"<< std::endl;
	std::cout << "[token_len] experiment: _max_token_len: "<< _max_token_len << std::endl;
#endif
	do
	{
		str.clear();
		for(unsigned short k=0; k < _max_token_len; k++)
		{
		    str.push_back(*_die++);
		      _die++;
		 }
	} while(!validate(str));

	pack();

	return str;
}
 

bool token::validate(const std::string& _str) 
{
	bool is_valid;
	

	if((*this).generator::_max_distr_value > 0x2F && (*this).generator::_min_distr_value < 0x3A)
		if(!(is_valid = token::check_rule_digit_in_string(_str)))
			return false;

	if(!(is_valid = token::check_rule_loosely_different_in_string(_str)))
	   	return false;

	if((*this).generator::_max_distr_value > 0x40 && (*this).generator::_min_distr_value < 0x5B)
		if(!(is_valid = token::check_rule_upper_in_string(_str)))
			return false;
	if((*this).generator::_max_distr_value > 0x60 && (*this).generator::_min_distr_value < 0x7B)
		if(!(is_valid = token::check_rule_lower_in_string(_str)))
	   		return false;

	if(((*this).generator::_max_distr_value > 0x20 && (*this).generator::_min_distr_value < 0x30) ||
		((*this).generator::_max_distr_value > 0x39 && (*this).generator::_min_distr_value < 0x41) ||
		((*this).generator::_max_distr_value > 0x5A && (*this).generator::_min_distr_value < 0x61) ||
		((*this).generator::_max_distr_value > 0x7A && (*this).generator::_min_distr_value < 0x7F)
		)
		if(!(is_valid= token::check_rule_punct_in_string(_str, allowed_punct, forbidden_punct, allow_first_as_punct)))
			return false;

	return is_valid;
	   
}

	
bool token::check_rule_digit_in_string(const std::string& _str)
{
	unsigned short j(0);

	// RENDIMAX needs at least 2 digits
	for(unsigned short k=0; k < _str.length() && j < 2; k++)
	{		
		j += isdigit(_str[k]) ? 1:0;		
	}

	return  j > 1;
}
	
bool token::check_rule_upper_in_string(const std::string& _str)
{
	unsigned short j(0);

	for(unsigned short k=0; k < _str.length() && j < 1; k++)
	{
		j+= isupper(_str[k])? 1:0;
	}
	   	
	return j > 0;
}
	
bool token::check_rule_lower_in_string(const std::string& _str)
{
	unsigned short j=0;
	
	for(unsigned short k=0; k < _str.length() && j < 1; k++)
	{
		j+= islower(_str[k]) ? 1:0;
	}
	   	
	return j > 0;
}


bool token::check_rule_punct_in_string(const std::string& _str, const std::string& _allowed_punct, const std::string& _forbidden_punct, bool _allow_first_as_punct)
{
	bool is_valid(true);
		
	if(ispunct(_str[0]))
		is_valid = _allow_first_as_punct;

	for(unsigned short k=0; is_valid && k < _str.length(); k++)		
	{		
		for(unsigned short j =0; ispunct(_str[k]) && !_allowed_punct.empty() && j < _allowed_punct.length(); )
		{
			if(_str[k] != _allowed_punct[j++])
					return false;	
		}
		
		for(unsigned short j =0; ispunct(_str[k]) && !_forbidden_punct.empty() && j < _forbidden_punct.length(); )
		{
			if(_str[k] == _forbidden_punct[j++])
					return false;	
		}
	}
	   	
	return is_valid;
}
	
bool token::check_rule_loosely_different_in_string(const std::string& _str)
{
	for(unsigned short k=0; _str.length() >1 && k < _str.length()-1; k++)
		if(_str[k] == _str[k+1])
			return false;
				
	return true;
}

/*

pin_token::pin_token(): token(MAX_TOKEN_LEN, 0x30, 0x39) {};

bool pin_token::validate(std::string& _str)
{
#ifdef _DEBUG
	std::cout << "\n[pin_token] validate: " << std::endl;
#endif 
	for(unsigned short k=0; k < _str.length(); k++)
	{
#ifdef _DEBUG
		std::cout << _str[k];
#endif
		if(!isdigit(_str[k]))
			return false;
	}

	return true;	
}



liberowebmail_token::liberowebmail_token(): token(MAX_LIBERO_TOKEN_LEN, 0x2D, 0x7A) {};

bool liberowebmail_token::validate(std::string& _str)
{
#ifdef _DEBUG
 std::cout << _str << std::endl;
#endif

	if(_str[0] == '.') return false;

	for(unsigned short k =0; k < _str.length(); k++)
	{
#ifdef _DEBUG
		std::cout << _str[k] << std::endl;
#endif
		if(!isalnum(_str[k]) && _str[k] != '.' && _str[k] != '-' && _str[k] != '_')
			return false;
	}

	return true;
}
   


gmail_token::gmail_token(unsigned short _len): token(_len, 0x21, 0x7E) {};
gmail_token::gmail_token(): token(MAX_GMAIL_TOKEN_LEN, 0x21, 0x7E) {};

bool gmail_token::validate(std::string& _str) 
{
	bool is_valid;
	
	if(!(is_valid = token::check_rule_digit_in_string(_str)))
		return false;

	if(!(is_valid = token::check_rule_upper_in_string(_str)))
		return false;

	if(!(is_valid = token::check_rule_lower_in_string(_str)))
	   	return false;

	if(!(is_valid = token::check_rule_punct_in_string(_str)))
		return false;

	if(!(is_valid = token::check_rule_loosely_different_in_string(_str)))
	   	return false;

	return is_valid;
	   
}



webbanking_token::webbanking_token(): gmail_token(MAX_TOKEN_LEN) {};
	
bool webbanking_token::validate(std::string& _str) 
{	  
	bool is_valid;	
	   
	if(!isalnum(_str[0])) return false;
	  
	if(!(is_valid = (*this).gmail_token::validate(_str)))
	{	
	   	return false;
	}	
	
	return is_valid;	
	   
}


visa_token::visa_token(): token(MAX_TOKEN_LEN, 0x21, 0x7E) {};
	
bool visa_token::validate(std::string& _str) 
{	  
	bool is_valid;
	   
	for(unsigned short k=0; k < _str.length(); k++)
		if(!(is_valid = isalnum(_str[k])))
			break;
	if(!is_valid) return false;
	   
	if(!(is_valid = token::check_rule_digit_in_string(_str)))
		return false;

	if(!(is_valid = token::check_rule_upper_in_string(_str)))
		return false;

	if(!(is_valid = token::check_rule_lower_in_string(_str)))
	   	return false;
		
	if(!(is_valid = token::check_rule_loosely_different_in_string(_str)))
	   	return false;

	return is_valid;	   
}

*/



